package me.like.diandian.util;


import java.net.SocketTimeoutException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import me.like.diandian.BaseApplication1;
import me.like.diandian.BuildConfig;
import me.like.diandian.api.ErrorVerify;
import me.like.diandian.api.SimpleErrorVerify;
import me.like.diandian.base.BaseContract;
import me.like.diandian.base.BaseModel;
import rx.Observable;
import rx.functions.Func1;

/**
 * Created by MLOONG on 2017/3/23.
 */

public class RxUtils {
    private static Scheduler scheduler;
    /**
     * 服务器返回错误码 1000为成功
     */
    public static final int REQUESTOK = 1000;   //请求后台成功

    public static final int REQUESTFLAG1 = 1011;  //请先登录

    public static final int REQUESTFLAG2 = 1012;  //登录超时

    public static final int REQUESTFLAG3 = 1013; //登录验证失败

    public static final int NET_ERROR = -1;     //网络错误

    //public static  final int REQUESTFLAG5 = 1004; //用户不存在

    /**
     * 简单的请求业务错误过滤器（弹出toast）
     */
    private static <T> Func1<T, Boolean> verifySimpleBusiness(BaseContract.BaseView context) {
        return verifyBusiness(new SimpleErrorVerify(context));
    }

    /**
     * 业务错误过滤器（自定义）
     */
    private static <T> Func1<T, Boolean> verifyBusiness(ErrorVerify errorVerify) {
        return response -> {
            if (response instanceof BaseModel) {
                BaseModel baseResponse = (BaseModel) response;
                boolean isSuccess = baseResponse.isSuccess();
                if (!isSuccess) {
                    if (errorVerify != null) {
                        errorVerify.call(Integer.parseInt(baseResponse.getCode()), baseResponse.getMsg());
                    }
                }
                return isSuccess;
            } else {
                return false;
            }
        };
    }

    /**
     * 非空过滤器（自定义）
     */
    private static <T> Func1<T, Boolean> verifyNotEmpty() {
        return response -> response != null;
    }

    /**
     * 错误提醒处理
     *
     * @param context
     * @param errorVerify
     * @param <T>
     * @return
     */
    private static <T> Func1<Throwable, T> doError(BaseContract.BaseView context, ErrorVerify errorVerify) {
        return throwable -> {
            throwable.printStackTrace();
            if (errorVerify != null) {
                if (!NetUtils.isConnected(BaseApplication1.getInstance())) {
                    errorVerify.call(NET_ERROR, "网络错误");

                } else {
                    errorVerify.call(0, generateErrorMsg(throwable));
                }
            }
            return null;
        };
    }


    /**
     * 优先使用这个，可以继续使用操作符
     */
    public static <T> Observable.Transformer<T, T> applySchedulers() {
        return observable -> observable
                .subscribeOn(rx.schedulers.Schedulers.io())
                .observeOn(rx.android.schedulers.AndroidSchedulers.mainThread());
    }

    /**
     * 聚合了session过滤器,业务过滤器及合并操作 自定义错误回调
     */
    public static <T> Observable.Transformer<T, T>
    applySchedulersAndAllFilter(BaseContract.BaseView context, ErrorVerify errorVerify) {
        return observable -> observable
                .compose(applySchedulers())
                .filter(verifyNotEmpty())
                .filter(verifyBusiness(errorVerify))
                .onErrorReturn(doError(context, errorVerify))
                .doOnCompleted(() -> {
//                    if (context instanceof BaseActivity)
//                        ((BaseActivity) context).dismissDialog();
                });
    }


    public static String generateErrorMsg(Throwable throwable) {
        if ("debug".equals(BuildConfig.BUILD_TYPE)) {
            return throwable != null ? throwable.getMessage() : "未知错误";
        } else if (throwable instanceof SocketTimeoutException) {
            return "网络连接超时";
        } else if (!NetUtils.isConnected(BaseApplication1.getInstance())) {
            return "您的网络不太给力哦";
        } else {
            return "系统繁忙，请稍后再试";
        }
    }

    /**
     * 聚合了session过滤器,简单业务过滤器及合并操作
     * 结果返回包含BaseModelNew的对象
     */
    public static <T> Observable.Transformer<T, T> applySchedulerAndAllFilter(BaseContract.BaseView context) {
        return applySchedulersAndAllFilter(context, new SimpleErrorVerify(context));
    }

    /**
     * 延时执行
     *
     * @param time
     * @param timeUnit
     * @param listener
     */
    public static Disposable delayDo(long time, TimeUnit timeUnit, NotifyListener listener) {
        if (time < 0) time = 0;
        return Flowable
                .timer(time, timeUnit)
                .compose(io2main())
                .subscribe((aLong -> {
                    listener.onNotify(null, null);
                }), Throwable::printStackTrace);

    }

    /**
     * 每隔一段时间执行
     *
     * @param time
     * @param timeUnit
     * @param listener
     * @return
     */
    public static Disposable intervel(int time, TimeUnit timeUnit, NotifyListener listener) {
        return Flowable
                .interval(0, time, timeUnit)
                .compose(io2main())
                .subscribe((aLong -> {
                    listener.onNotify(null, null);
                }), Throwable::printStackTrace);


    }
    public static <T> FlowableTransformer<T, T> io2main() {
        if (scheduler==null){
            scheduler = Schedulers.from(new ThreadPoolExecutor(7, 20, 20L,
                    TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(64)
                    , new ThreadPoolExecutor.DiscardOldestPolicy()));
        }
        return tObservable -> tObservable.subscribeOn(scheduler).unsubscribeOn(scheduler).observeOn(AndroidSchedulers.mainThread());
    }
}

